在初步暸解全連接神經網絡 (Fully Connected Neural Network) 後,接下來必須介紹的經典架構就是卷積神經網絡 (Convolutional Neural Network; CNN)。卷積神經網絡可以說是深度學習的代表性架構之一,特別是在電腦視覺 (Computer Vision) 領域幾乎無處不在。
在我們的日常生活中,從手機的人臉辨識、影像搜尋、自駕車的影像識別,到醫學影像的腫瘤檢測,都可以看到卷積神經網絡的身影。它能在海量影像資料中自動學習特徵,避免了傳統機器學習需要人工設計特徵的困難。
在前面介紹的 全連接神經網路 (Fully Connected Neural Network, FCNN) 中,我們知道每一層神經元都與上一層的所有輸入相連。但如果我們把輸入換成圖片,就會發現一個很大的問題:
CNN 主要由以下幾種層組成:
CNN 常使用 ReLU (Rectified Linear Unit),定義為:
$$
f(x)=max(0,x)
$$
其優點是計算簡單,能有效避免梯度消失問題。
為了提升模型的泛化能力,常見技術包括:
舉例來說,假設我們要用 CNN 辨識一張手寫數字圖片,流程可能是:
給大家看一下就好,跟上一個實作差不多,只是改成 CNN 來預測,讓準確度可以在提升
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
# ---------------------------
# 1. 資料預處理與載入
# ---------------------------
transform = transforms.Compose([
transforms.ToTensor(), # 轉成 tensor
transforms.Normalize((0.1307,), (0.3081,)) # 標準化 MNIST 平均值與標準差
])
train_dataset = datasets.MNIST(root="./data", train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root="./data", train=False, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=1000, shuffle=False)
# ---------------------------
# 2. 定義 CNN 模型
# ---------------------------
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
# Conv2d(輸入通道數, 輸出通道數, kernel大小)
self.conv1 = nn.Conv2d(1, 32, 3, 1) # (28x28 -> 26x26)
self.conv2 = nn.Conv2d(32, 64, 3, 1) # (26x26 -> 24x24)
self.dropout1 = nn.Dropout(0.25)
self.dropout2 = nn.Dropout(0.5)
self.fc1 = nn.Linear(9216, 128) # 64*12*12 = 9216
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = self.conv1(x)
x = F.relu(x)
x = self.conv2(x)
x = F.relu(x)
x = F.max_pool2d(x, 2) # (24x24 -> 12x12)
x = self.dropout1(x)
x = torch.flatten(x, 1) # 攤平成一維
x = self.fc1(x)
x = F.relu(x)
x = self.dropout2(x)
x = self.fc2(x)
output = F.log_softmax(x, dim=1) # 分類用 softmax
return output
model = CNN()
# ---------------------------
# 3. 訓練與測試流程
# ---------------------------
optimizer = optim.Adam(model.parameters(), lr=0.001)
def train(model, device, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data, target
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
if batch_idx % 100 == 0:
print(f"Train Epoch: {epoch} [{batch_idx*len(data)}/{len(train_loader.dataset)}] Loss: {loss.item():.6f}")
def test(model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
output = model(data)
test_loss += F.nll_loss(output, target, reduction='sum').item()
pred = output.argmax(dim=1, keepdim=True)
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
accuracy = 100. * correct / len(test_loader.dataset)
print(f"Test set: Avg loss: {test_loss:.4f}, Accuracy: {correct}/{len(test_loader.dataset)} ({accuracy:.2f}%)\n")
# ---------------------------
# 4. 開始訓練
# ---------------------------
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
for epoch in range(1, 6): # 訓練 5 個 epoch
train(model, device, train_loader, optimizer, epoch)
test(model, device, test_loader)
卷積神經網路之所以能成為深度學習領域的核心技術之一,關鍵在於它善於處理具有空間結構的資料。透過卷積層提取局部特徵、池化層降低維度並保留關鍵資訊,CNN 能有效捕捉圖像、語音等資料中的模式,避免傳統全連接網路因高維度而產生的參數爆炸問題。
以 MNIST 手寫數字辨識為例,CNN 在短短幾個 epoch 內即可達到 98% 以上的準確率,遠優於單純的全連接網路。這顯示 CNN 的結構不僅能提升模型性能,也能在計算效率上取得平衡。
然而,CNN 並非萬能。當資料缺乏明確的局部結構 (例如純結構化數值資料),卷積層的優勢就不明顯;同時,CNN 的運算資源需求相對較高,對硬體 (GPU) 有一定依賴。
總體來說,CNN 已經成為影像辨識與電腦視覺任務的標準解法,後續更衍生出 ResNet、Inception、EfficientNet 等更深更複雜的架構。對初學者而言,理解 CNN 的核心概念 (卷積、池化、權重共享、特徵提取) 是踏入深度學習應用的第一步;對進階研究者而言,則需要進一步思考如何結合 CNN 與其他模型 (如 Transformer) 來應對更複雜的任務。